/*******************************************************************************
 * Copyright (c) 2009 Kevin Bierhoff and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Kevin Bierhoff - initial API and implementation
 *******************************************************************************/
package com.googlecode.twelfdevtools.views;

import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationModelEvent;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelListener;
import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import com.googlecode.twelfdevtools.model.IElfFile;
import com.googlecode.twelfdevtools.model.TwelfModel;
import com.googlecode.twelfdevtools.util.UIUtil;

public class ElfFileOutline extends ContentOutlinePage implements
		IContentOutlinePage, IAnnotationModelListener, IAnnotationModelListenerExtension {

	private ISourceViewer sourceViewer;

	public ElfFileOutline(ISourceViewer sourceViewer) {
		this.sourceViewer = sourceViewer;
	}

	@Override
	public void createControl(Composite parent) {
		super.createControl(parent);
		getTreeViewer().setContentProvider(new ElfFileContentProvider());
		getTreeViewer().setLabelProvider(new TwelfModelLabelProvider());
		getTreeViewer().setInput(getFileModel());
		getTreeViewer().expandAll();
		
		// register with annotation model
		UIUtil.getAnnotationModel(sourceViewer).addAnnotationModelListener(this);
	}
	
	@Override
	public void dispose() {
		// de-register from annotation model
		if(sourceViewer != null)
			UIUtil.getAnnotationModel(sourceViewer).removeAnnotationModelListener(this);
	}

	public IElfFile getFileModel() {
		if(sourceViewer != null) {
			return TwelfModel.getModel().getFileModel(sourceViewer);
		}
		else return null;
	}

	
	public void modelChanged(IAnnotationModel annoModel) {
		// this method is superseded with IAnnotationModelListenerExtension
		// but we provide it anyway just in case.
		if(getTreeViewer() != null && sourceViewer != null) {
			final IElfFile model = getFileModel();
			// update tree in UI thread
			// apparently not all model changes are signaled in the UI thread
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					ElfFileOutline.this.getTreeViewer().setInput(model);
				}
			});
		}
	}

	public void modelChanged(AnnotationModelEvent event) {
		if(! event.isEmpty() && event.isValid()) {
			// re-set model when annotation model changes
			// TODO may have to make this more efficient
			// TODO maybe update file model in place and have listener for that?
			if(getTreeViewer() != null && sourceViewer != null) {
				
				viewerUpdateNeeded:
				if (! event.isWorldChange()) {
					for (Annotation a : event.getAddedAnnotations()) {
						if (a instanceof MarkerAnnotation)
							break viewerUpdateNeeded;
					}
					for (Annotation a : event.getRemovedAnnotations()) {
						if (a instanceof MarkerAnnotation)
							break viewerUpdateNeeded;
					}
					for (Annotation a : event.getChangedAnnotations()) {
						if (a instanceof MarkerAnnotation)
							break viewerUpdateNeeded;
					}
					// no markers changed so we don't need to update the outline
					// in particular, this prevents occurrence markers from updating the outline
					return;
				}

				final IElfFile model = getFileModel();
				// update tree in UI thread
				// apparently not all model changes are signaled in the UI thread
				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						ElfFileOutline.this.getTreeViewer().setInput(model);
					}
				});
			}
		}
	}

}
